package cn.birdbaby.plugins.annotator;

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationMemberValue;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Map;

/**
 * @author llorando 8/8/24 11:56 am
 */
public abstract class AbstractAnnotator implements IAnnotator {
    public abstract Map<String, PsiAnnotationMemberValue> buildAnnotationContent(Context context);

    public PsiAnnotation buildPsiAnnotation(Context context) {
        return WriteCommandAction.runWriteCommandAction(context.getProject(), (Computable<PsiAnnotation>) () -> {
            PsiAnnotation tmp = context.getPsiModifierList().addAnnotation(getSimpleName());
            Map<String, PsiAnnotationMemberValue> valueMap = buildAnnotationContent(context);
            if (valueMap.isEmpty()) return tmp;
            // Set the pkgName attribute
            valueMap.forEach((k, v) ->
                    tmp.setDeclaredAttributeValue(k, v)
            );
            return tmp;
        });
    }

    @Override
    public boolean support(PsiElement element) {
        Collection<PsiAnnotation> psiAnnotations = ReadAction.compute(() -> PsiTreeUtil.findChildrenOfAnyType(element, PsiAnnotation.class));
        if (CollectionUtils.isEmpty(psiAnnotations)) return true;
        for (PsiAnnotation psiAnnotation : psiAnnotations) {
            String referenceName = ReadAction.compute(() -> {
                PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement();
                return nameReferenceElement.getReferenceName();
            });
            if (StringUtils.startsWithIgnoreCase(referenceName, getSimpleName())) {
                return false;
            }
        }
        return true;
    }
}
